<?php
/**
 * 访问控制列表 (ACL,Access Control List)
 * 
 * <pre>
 *	import("net.4kiki.acl.*");
 *	
 *	//创建Acl
 *	$acl = new IAcl("acl");
 *	$acl->addResources(array("/index", "/my", "/user"));
 *	$acl->addRoles(array("guest", "user", "admin"));
 *	
 *	//添加关联关系
 *	$acl->allow("/index", "guest");
 *	$acl->allow("/my", "admin");
 *	
 *	//判断是否能执行
 *	if($acl->isAllowed("/index", "guest")) {
 *		echo "allowed";
 *	}
 *	else {
 *		echo "denied";
 *	}
 * </pre>
 *
 * @since 0.1
 * @package net.4kiki.acl
 */
class IAcl extends IObject {
	private $resources = array();
	private $roles = array();
	private static $acls = array();
	
	/**
	 * 构造器
	 *
	 * @param string $name 名称
	 * @since 0.1
	 */
	public function __construct($name) {
		self::$acls[$name] = $this;
	}
	
	/**
	 * 取得Acl列表
	 *
	 * @param string $name 名称
	 * @return IAcl
	 * @since 0.1
	 */
	public static function getAcl($name) {
		if (array_key_exists($name, self::$acls)) {
			return self::$acls[$name];
		}
		return null;
	}
	
	/**
	 * 添加资源
	 *
	 * @param IAclResource $resource 资源
	 * @since 0.1
	 */
	public function addResource(IAclResource $resource) {
		$this->resources[$resource->getName()] = $resource;
	}
	
	/**
	 * 添加一组资源
	 *
	 * @param array $resources 资源
	 * @since 0.1
	 */
	public function addResources (array $resources) {
		foreach ($resources as $resource) {
			if ($resource instanceof IAclResource) {
				$this->addResource($resource);
			}
			else {
				$this->addResource(new IAclResource($resource));
			}
		}
	}
	
	/**
	 * 添加一组角色
	 *
	 * @param array $roles 角色
	 * @since 0.1
	 */
	public function addRoles (array $roles) {
		foreach ($roles as $role) {
			if ($role instanceof IAclRole) {
				$this->addRole($role);
			}
			else {
				$this->addRole(new IAclRole($role));
			}
		}
	}	
	
	/**
	 * 添加角色
	 *
	 * @param IAclRole $role 角色
	 * @since 0.1
	 */
	public function addRole(IAclRole $role) {
		$this->roles[$role->getName()] = $role;
	}
	
	/**
	 * 判断是否允许执行某个资源
	 *
	 * @param string $resourceName 资源名
	 * @param string $roleName 角色名
	 * @return boolean
	 * @since 0.1
	 */
	public function isAllowed($resourceName, $roleName) {
		if (!array_key_exists($resourceName, $this->resources)) {
			throw new IAclException("resource '{$resourceName}' does not exist");
		}
		$resource = $this->resources[$resourceName];
		if (!array_key_exists($roleName, $this->roles)) {
			throw new IAclException("role '{$roleName}' does not exist");
		}
		$role = $this->roles[$roleName];
		return $role->isAllowed($resource);
	}
	
	/**
	 * 取得所有资源
	 *
	 * @return array
	 * @since 0.1
	 */
	public function getResources() {
		return $this->resources;
	}
	
	/**
	 * 取得所有角色
	 *
	 * @return array
	 * @since 0.1
	 */
	public function getRoles() {
		return $this->roles;
	}
	
	/**
	 * 取得资源
	 *
	 * @param string $name 资源名
	 * @return IAclResource
	 * @since 0.1
	 */
	public function getResource($name) {
		if (array_key_exists($name, $this->resources)) {
			return $this->resources[$name];
		}
		return null;
	}
	
	/**
	 * 取得角色
	 *
	 * @param string $name 角色名
	 * @return IAclRole
	 * @since 0.1
	 */
	public function getRole($name) {
		if (array_key_exists($name, $this->roles)) {
			return $this->roles[$name];
		}
		return null;
	}
	
	/**
	 * 允许某个角色执行某个资源
	 *
	 * @param string $resourceName 资源名
	 * @param string $roleName 角色名
	 * @return boolean
	 * @since 0.1
	 */
	public function allow($resourceName, $roleName) {
		if (!array_key_exists($resourceName, $this->resources)) {
			throw new IAclException("resource '{$resourceName}' does not exist");
		}
		$resource = $this->resources[$resourceName];
		if (!array_key_exists($roleName, $this->roles)) {
			throw new IAclException("role '{$roleName}' does not exist");
		}
		$role = $this->roles[$roleName];
		$role->allow($resource);
	}
	
	/**
	 * 禁止某个角色执行某个资源
	 *
	 * @param string $resourceName 资源名
	 * @param string $roleName 角色名
	 * @return boolean
	 * @since 0.1
	 */
	public function deny($resourceName, $roleName) {
		if (!array_key_exists($resourceName, $this->resources)) {
			throw new IAclException("resource '{$resourceName}' does not exist");
		}
		$resource = $this->resources[$resourceName];
		if (!array_key_exists($roleName, $this->roles)) {
			throw new IAclException("role '{$roleName}' does not exist");
		}
		$role = $this->roles[$roleName];
		$role->deny($resource);
	}	
}

?>